package noodws

import (
	"errors"
	"github.com/spf13/cast"
	"go.uber.org/zap"
	"nood/noodframe/noodlog"
	"sync"
	"time"
)

// 保存所有在线用户
var userClientMap sync.Map

// 绑定用户id与ws客户端的关系
func SetUserClientMap(uid int64, client *WsContext) {
	userClientMap.Store(uid, client)
}

// 解除绑定关系
func DelUserClientMap(uid int64) {
	userClientMap.Delete(uid)
}

// 根据用户id获取ws连接
func GetUserClientMap(uid int64) (*WsContext, error) {
	if v, ok := userClientMap.Load(uid); ok {
		return v.(*WsContext), nil
	}
	return nil, errors.New("uid 错误")
}

// 批量推送信息到客户端
func BatchSendToClient(uid []int64, cmd string, data interface{}) error {
	response := setResponse(cmd, cast.ToString(time.Now().Unix()), data)
	for _, v := range uid {
		if err := send(v, response); err != nil {
			noodlog.Debug("BatchSendToClient", zap.Any("err", err), zap.Any("uid", uid), zap.Any("response", response))
		}
	}

	return nil
}

// 推送信息到客户端
func SendToClient(uid int64, cmd string, data interface{}) error {
	response := setResponse(cmd, cast.ToString(time.Now().Unix()), data)
	if err := send(uid, response); err != nil {
		noodlog.Debug("SendToClient", zap.Any("err", err), zap.Any("uid", uid), zap.Any("response", response))
	}
	return nil
}

// 发送错误信息到客户端
func SendErrorToClient(uid int64, cmd string, code int32, Msg string) error {
	response := setError(cmd, cast.ToString(time.Now().Unix()), code, Msg)
	if err := send(uid, response); err != nil {
		noodlog.Debug("SendErrorToClient", zap.Any("err", err), zap.Any("uid", uid), zap.Any("response", response))
	}
	return nil
}

// 发送带有参数的错误信息到客户端
func SendErrorAndDataToClient(uid int64, cmd string, code int32, Msg string, data interface{}) error {
	response := setErrorAndData(cmd, cast.ToString(time.Now().Unix()), code, Msg, data)
	if err := send(uid, response); err != nil {
		noodlog.Debug("SendErrorToClient", zap.Any("err", err), zap.Any("uid", uid), zap.Any("response", response))
	}
	return nil
}

// 发送错误码到客户端
func SendErrorCodeToClient(uid int64, cmd string, code int32) error {
	response := setErrorCode(cmd, cast.ToString(time.Now().Unix()), code)
	if err := send(uid, response); err != nil {
		noodlog.Debug("SendErrorCodeToClient", zap.Any("err", err), zap.Any("uid", uid), zap.Any("response", response))
	}
	return nil
}

// 推送消息
func send(uid int64, data interface{}) error {
	userClient, err := GetUserClientMap(uid)
	if err == nil {
		sendData := &sendDataChanType{
			WsC:  userClient,
			Data: data,
		}
		sendDataChan <- sendData
	}
	return err
}

type sendDataChanType struct {
	WsC  *WsContext
	Data interface{}
}

var sendDataChan = make(chan *sendDataChanType)

func PushToClient() {
	for userClient := range sendDataChan {
		err := userClient.WsC.Client.WriteJSON(userClient.Data)
		if err != nil {
			userClient.WsC.closeWs()
		}
	}
}
